Se estudian en el módulo 12 de Python lo referente a la clasificación de datos mediante los métodos K-medias y Clusterización Jerárquica.
El algoritmo K-medias propuesto por MacQueen en el año 1967 es un algoritmo que permite descubrir agrupamientos en conjuntos de datos.
K-medias es un método que tiene como objetivo generar una partición de un conjunto de n observaciones en k grupos. Cada grupo está representado por el promedio de los puntos que lo componen. El representante de cada grupo se denomina centroide. La cantidad de grupos a descubrir, k, es un parámetro que se debe fijar al ajecutar el método.
El método de clasificación (clustering en inglés) comienza a partir de k centroides ubicados de forma aleatoria, y asigna cada observación al centroide más “cercano”. La forma de determinar esta “cercanía” podría depender del tipo de datos.
Es posible por ello establecer una “distancia” equivalente/adecuada en el plano o espacio (vectorial) al que pertenecen los datos. Es por ello, que a pesar de que la distancia euclidiana es por definición la que se supone, pueden determinarse métodos externos que permitan calcular una “distancia” que sea más adecuada al tipo de los datos.
Después de asignar los centroides, estos se deben ir moviendoa a una ubicación que sea el promedio de todos los datos asignados a este centroide. Luego se reptite el algoritmo reasignando los puntos de acuerdo a las nuevas posiciones de los centroides. Los datos no se cambian, se corrige el centroide. Se busca que los datos asociados a un centroide estén lo mas cercanos a este centroida además que los grupos estén lo más separados entre ellos.
El objetivo de K-medias es agrupar a las observaciones de forma tal que todas las que se encuentren en el mismo grupo sean lo más cercanas (semejantes) entre sí y que las pertenecientes a grupos distintos sean lo más distantes (distintas) entre sí. Las medidas de distancia, como se indicó anteriormente, suele ser la euclídea, y son utilizadas para medir la distancia. Una medida para indicar cuán bien los centroides representan a los miembros de su grupo es la suma de los errores al cuadrado.
Y para ello en K-medias, cada iteración intenta reducir el valor de este error. La medida euclidiana consiste en la sumatoria de las distancias al cuadrado de cada observación con el “centroide” propuesto con respecto a determinado grupo.
El algoritmo podría dar resultados mejores en algunas “corridas” que en otras debido a la aletoriedad del inicio. Es común que los índices obtenidos para los grupos en diferentes corridas se intercambien (numéricamente) y los datos queden agrupados de la misma forma. Además el método podría no ser óptimo.
import os
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
from sklearn.datasets import make_blobs
from sklearn.cluster import KMeans
import numpy as np
from math import pi
import mglearn
# Plotea un ejemplo de ejecución del algoritmo k-medias
mglearn.plots.plot_kmeans_algorithm()
plt.show()
plt.close()
# Plotea las fonteras de clases (diagrama de Voronoi)
mglearn.plots.plot_kmeans_boundaries()
plt.show()
plt.close()
# Un ejemplo con datos sinteticos
# Ejemplo 1. Datos simlados en 2 variables
X, y = make_blobs(random_state=1)
print(X[0:10]) # Datos
## [[ -0.79415228 2.10495117]
## [ -9.15155186 -4.81286449]
## [-11.44182631 -4.45781441]
## [ -9.76761777 -3.19133737]
## [ -4.53655648 -8.40186288]
## [ -6.26302115 -8.10666081]
## [ -6.38481234 -8.4730297 ]
## [ -9.20490564 -4.57687928]
## [ -2.76017908 5.55121358]
## [ -1.17104176 4.33091816]]
print(y) # Cluster
# Construye un modelo k-medias
## [0 1 1 1 2 2 2 1 0 0 1 1 2 0 2 2 2 0 1 1 2 1 2 0 1 2 2 0 0 2 0 0 2 0 1 2 1
## 1 1 2 2 1 0 1 1 2 0 0 0 0 1 2 2 2 0 2 1 1 0 0 1 2 2 1 1 2 0 2 0 1 1 1 2 0
## 0 1 2 2 0 1 0 1 1 2 0 0 0 0 1 0 2 0 0 1 1 2 2 0 2 0]
kmeans = KMeans(n_clusters=3)
kmeans.fit(X)
# Cluster al que pertenece al que asigna k-medias (dos formas de hacerlo)
## KMeans(n_clusters=3)
print("Cluster al que pertenece cada individuo:\n{}".format(kmeans.labels_))
## Cluster al que pertenece cada individuo:
## [0 2 2 2 1 1 1 2 0 0 2 2 1 0 1 1 1 0 2 2 1 2 1 0 2 1 1 0 0 1 0 0 1 0 2 1 2
## 2 2 1 1 2 0 2 2 1 0 0 0 0 2 1 1 1 0 1 2 2 0 0 2 1 1 2 2 1 0 1 0 2 2 2 1 0
## 0 2 1 1 0 2 0 2 2 1 0 0 0 0 2 0 1 0 0 2 2 1 1 0 1 0]
print(kmeans.predict(X))
# Plotea el resultado
# Es posible directamente porque solo hay dos variables
## [0 2 2 2 1 1 1 2 0 0 2 2 1 0 1 1 1 0 2 2 1 2 1 0 2 1 1 0 0 1 0 0 1 0 2 1 2
## 2 2 1 1 2 0 2 2 1 0 0 0 0 2 1 1 1 0 1 2 2 0 0 2 1 1 2 2 1 0 1 0 2 2 2 1 0
## 0 2 1 1 0 2 0 2 2 1 0 0 0 0 2 0 1 0 0 2 2 1 1 0 1 0]
null=mglearn.discrete_scatter(X[:, 0], X[:, 1], kmeans.labels_, markers='o')
null=mglearn.discrete_scatter( kmeans.cluster_centers_[:, 0],
kmeans.cluster_centers_[:, 1],
[0, 1, 2],
markers='^', markeredgewidth=2)
plt.show()
plt.close()
mglearn.plots.plot_kmeans_boundaries()
plt.show()
plt.close()
# Ejemplo 2. Datos de Estudiantes
#os.chdir("/Users/oldemarrodriguez/Google Drive/MDCurso/Datos")
#os.chdir("./Datos")
print(os.getcwd())
## /Users/freddy/Documents/Cursos/UCR/IE_0217/CursoVerano/MaterialCurso/Clases/Semana07/pyClase20/pyModulo12
datos = pd.read_csv('../Datos/EjemploEstudiantes.csv',delimiter=';',decimal=",",index_col=0)
print(datos)
## Matematicas Ciencias Espanol Historia EdFisica
## Lucia 7.0 6.5 9.2 8.6 8.0
## Pedro 7.5 9.4 7.3 7.0 7.0
## Ines 7.6 9.2 8.0 8.0 7.5
## Luis 5.0 6.5 6.5 7.0 9.0
## Andres 6.0 6.0 7.8 8.9 7.3
## Ana 7.8 9.6 7.7 8.0 6.5
## Carlos 6.3 6.4 8.2 9.0 7.2
## Jose 7.9 9.7 7.5 8.0 6.0
## Sonia 6.0 6.0 6.5 5.5 8.7
## Maria 6.8 7.2 8.7 9.0 7.0
print(datos.head())
## Matematicas Ciencias Espanol Historia EdFisica
## Lucia 7.0 6.5 9.2 8.6 8.0
## Pedro 7.5 9.4 7.3 7.0 7.0
## Ines 7.6 9.2 8.0 8.0 7.5
## Luis 5.0 6.5 6.5 7.0 9.0
## Andres 6.0 6.0 7.8 8.9 7.3
print(datos.shape)
# Ejecuta k-medias con 3 clusters
## (10, 5)
kmedias = KMeans(n_clusters=3)
kmedias.fit(datos)
## KMeans(n_clusters=3)
print(kmedias.predict(datos))
## [0 1 1 2 0 1 0 1 2 0]
centros = np.array(kmedias.cluster_centers_)
print(centros)
# Plotea Centro 1
## [[6.525 6.525 8.475 8.875 7.375]
## [7.7 9.475 7.625 7.75 6.75 ]
## [5.5 6.25 6.5 6.25 8.85 ]]
c1 = centros[:1, :]
print(c1)
## [[6.525 6.525 8.475 8.875 7.375]]
y=c1.tolist()[0]
print(y)
## [6.525, 6.525, 8.475, 8.875, 7.375]
N = len(y)
print(N)
## 5
x = range(N)
print(x)
## range(0, 5)
width = 1/1.5
colores_1 = ['#CF8EF8', '#523C81', '#D2D132', '#59C951', '#E5826C']
null=plt.bar(x, y, width, color=colores_1)
null=plt.xticks(range(datos.shape[1]), datos.columns)
plt.show()
plt.close()
# Plotea Centro 2
c2 = centros[1:2, :]
y=c2.tolist()[0]
N = len(y)
x = range(N)
width = 1/1.5
null=plt.bar(x, y, width, color=colores_1)
null=plt.xticks(range(datos.shape[1]), datos.columns)
plt.show()
plt.close()
# Plotea Centro 3
c3 = centros[2:3, :]
y=c3.tolist()[0]
N = len(y)
x = range(N)
width = 1/1.5
null=plt.bar(x, y, width, color=colores_1)
null=plt.xticks(range(datos.shape[1]), datos.columns)
plt.show()
plt.close()
# LOS TRES JUNTOS
colores_1 = ['#CF8EF8', '#523C81', '#D2D132', '#59C951', '#E5826C']
plt.figure(1,figsize=(18,8))
# Plotea Centro 1
plt.subplot(1, 3, 1)
y = centros[:1, :].tolist()[0]
null=plt.bar(range(len(y)), y, 1/1.5, color=colores_1)
null=plt.xticks(range(datos.shape[1]), datos.columns)
# Plotea Centro 2
plt.subplot(1, 3, 2)
y= centros[1:2, :].tolist()[0]
null=plt.bar(range(len(y)), y, 1/1.5, color=colores_1)
null=plt.xticks(range(datos.shape[1]), datos.columns)
# Plotea Centro 3
plt.subplot(1, 3, 3)
y = centros[2:3, :].tolist()[0]
null=plt.bar(range(len(y)), y, 1/1.5, color=colores_1)
null=plt.xticks(range(datos.shape[1]), datos.columns)
#Todos juntos
plt.show()
plt.close()
# RADAR PLOT para interpretar
# ===========================
datos
## Matematicas Ciencias Espanol Historia EdFisica
## Lucia 7.0 6.5 9.2 8.6 8.0
## Pedro 7.5 9.4 7.3 7.0 7.0
## Ines 7.6 9.2 8.0 8.0 7.5
## Luis 5.0 6.5 6.5 7.0 9.0
## Andres 6.0 6.0 7.8 8.9 7.3
## Ana 7.8 9.6 7.7 8.0 6.5
## Carlos 6.3 6.4 8.2 9.0 7.2
## Jose 7.9 9.7 7.5 8.0 6.0
## Sonia 6.0 6.0 6.5 5.5 8.7
## Maria 6.8 7.2 8.7 9.0 7.0
centros
## array([[6.525, 6.525, 8.475, 8.875, 7.375],
## [7.7 , 9.475, 7.625, 7.75 , 6.75 ],
## [5.5 , 6.25 , 6.5 , 6.25 , 8.85 ]])
centros_trans = centros.T
centros_trans
## array([[6.525, 7.7 , 5.5 ],
## [6.525, 9.475, 6.25 ],
## [8.475, 7.625, 6.5 ],
## [8.875, 7.75 , 6.25 ],
## [7.375, 6.75 , 8.85 ]])
V1 = centros_trans[:1,:]
print(V1)
## [[6.525 7.7 5.5 ]]
V1=V1.tolist()[0]
print(V1)
## [6.525, 7.7, 5.5]
V2 = centros_trans[1:2,:]
print(V2)
## [[6.525 9.475 6.25 ]]
V2=V2.tolist()[0]
print(V2)
## [6.525, 9.475, 6.25]
V3 = centros_trans[2:3,:]
print(V3)
## [[8.475 7.625 6.5 ]]
V3=V3.tolist()[0]
print(V3)
## [8.475, 7.625, 6.5]
V4 = centros_trans[3:4,:]
print(V4)
## [[8.875 7.75 6.25 ]]
V4=V4.tolist()[0]
print(V4)
## [8.875, 7.75, 6.25]
V5 = centros_trans[4:5,:]
print(V5)
## [[7.375 6.75 8.85 ]]
V5=V5.tolist()[0]
print(V5)
# Datos para el Radar Plot
## [7.375, 6.75, 8.85]
df = pd.DataFrame({
'grupo': ['Cluster-1','Cluster-2','Cluster-3'],
'Matematicas': V1,
'Ciencias': V2,
'Espanol': V3,
'Historia': V4,
'EdFisica': V5
})
print(df)
#Otra forma de hacer lo mismo:
## grupo Matematicas Ciencias Espanol Historia EdFisica
## 0 Cluster-1 6.525 6.525 8.475 8.875 7.375
## 1 Cluster-2 7.700 9.475 7.625 7.750 6.750
## 2 Cluster-3 5.500 6.250 6.500 6.250 8.850
df = pd.DataFrame()
for i in range(datos.shape[1]):
df = pd.concat([df,pd.DataFrame({datos.columns[i]:centros_trans[i,:].tolist()})],axis = 1)
df = pd.concat([df,pd.DataFrame({'grupo': ['Cluster-1','Cluster-2','Cluster-3']})],axis = 1)
print(df)
# Variables y Número de Variables
## Matematicas Ciencias Espanol Historia EdFisica grupo
## 0 6.525 6.525 8.475 8.875 7.375 Cluster-1
## 1 7.700 9.475 7.625 7.750 6.750 Cluster-2
## 2 5.500 6.250 6.500 6.250 8.850 Cluster-3
variables=list(df)[0:5]
print(variables)
## ['Matematicas', 'Ciencias', 'Espanol', 'Historia', 'EdFisica']
N = len(variables)
print(N)
# Ángulo de los ejes
## 5
angulos = [n / float(N) * 2 * pi for n in range(N)]
angulos+= angulos[:1]
# Inicializa el Radar
ax = plt.subplot(111, polar=True)
# En primer eje en la parte de arriba
ax.set_theta_offset(pi / 2)
ax.set_theta_direction(-1)
# Dibuja los ejes por variables + las etiquetas
null=plt.xticks(angulos[:-1], variables)
# Dibuja las etiquetas en Y
ax.set_rlabel_position(0)
null=plt.yticks([1,2,3,4,5,6,7,8,9,10], ["1","2","3","4","5","6","7","8","9","10"], color="grey", size=7)
plt.ylim(0,10)
# Plotea cada cluster (grupo) = una línea de datos
# Cluster 1
## (0.0, 10.0)
valores=df.loc[0].drop('grupo').values.flatten().tolist()
valores += valores[:1]
ax.plot(angulos, valores, linewidth=1, linestyle='solid', label="Cluster-1")
ax.fill(angulos, valores, 'b', alpha=0.1)
# Cluster 2
valores=df.loc[1].drop('grupo').values.flatten().tolist()
valores += valores[:1]
ax.plot(angulos, valores, linewidth=1, linestyle='solid', label="Cluster-2")
ax.fill(angulos, valores, 'r', alpha=0.1)
# Cluster 3
valores=df.loc[2].drop('grupo').values.flatten().tolist()
valores += valores[:1]
ax.plot(angulos, valores, linewidth=1, linestyle='solid', label="Cluster-3")
ax.fill(angulos, valores, 'b', alpha=0.1)
# Agrega la leyenda
plt.legend(loc='upper right', bbox_to_anchor=(0.1, 0.1))
plt.show()
plt.close()
# Los dibuja sobre el plano principal los clusters de k-medias
pca = PCA(n_components=2)
componentes = pca.fit_transform(datos)
componentes
## array([[-0.76471745, -1.5817637 ],
## [ 1.66887794, 1.39196556],
## [ 1.57822841, 0.29949595],
## [-2.60701317, 1.32020402],
## [-1.43877557, -1.33566867],
## [ 2.34790534, 0.3880845 ],
## [-0.89372557, -1.51890124],
## [ 2.64984571, 0.4254636 ],
## [-2.62959083, 2.18339513],
## [ 0.08896518, -1.57227516]])
print(datos.shape)
## (10, 5)
print(componentes.shape)
## (10, 2)
plt.scatter(componentes[:, 0], componentes[:, 1],c=kmedias.predict(datos))
plt.xlabel('componente 1')
plt.ylabel('componente 2')
plt.title('3 Cluster K-Medias')
plt.show()
plt.close()
# Ejemplo 3. Datos de Iris
iris = pd.read_csv('../Datos/iris.csv',delimiter=';',decimal=".")
print(iris)
## s.largo s.ancho p.largo p.ancho tipo
## 0 5.1 3.5 1.4 0.2 setosa
## 1 4.9 3.0 1.4 0.2 setosa
## 2 4.7 3.2 1.3 0.2 setosa
## 3 4.6 3.1 1.5 0.2 setosa
## 4 5.0 3.6 1.4 0.2 setosa
## .. ... ... ... ... ...
## 145 6.7 3.0 5.2 2.3 virginica
## 146 6.3 2.5 5.0 1.9 virginica
## 147 6.5 3.0 5.2 2.0 virginica
## 148 6.2 3.4 5.4 2.3 virginica
## 149 5.9 3.0 5.1 1.8 virginica
##
## [150 rows x 5 columns]
iris.head()
## s.largo s.ancho p.largo p.ancho tipo
## 0 5.1 3.5 1.4 0.2 setosa
## 1 4.9 3.0 1.4 0.2 setosa
## 2 4.7 3.2 1.3 0.2 setosa
## 3 4.6 3.1 1.5 0.2 setosa
## 4 5.0 3.6 1.4 0.2 setosa
iris.shape
# Ejecuta k-medias con 3 clusters
## (150, 5)
kmedias = KMeans(n_clusters=3)
iris_tempo=iris.iloc[:,:4]
iris_tempo
## s.largo s.ancho p.largo p.ancho
## 0 5.1 3.5 1.4 0.2
## 1 4.9 3.0 1.4 0.2
## 2 4.7 3.2 1.3 0.2
## 3 4.6 3.1 1.5 0.2
## 4 5.0 3.6 1.4 0.2
## .. ... ... ... ...
## 145 6.7 3.0 5.2 2.3
## 146 6.3 2.5 5.0 1.9
## 147 6.5 3.0 5.2 2.0
## 148 6.2 3.4 5.4 2.3
## 149 5.9 3.0 5.1 1.8
##
## [150 rows x 4 columns]
kmedias.fit(iris_tempo)
## KMeans(n_clusters=3)
print(kmedias.predict(iris_tempo))
## [1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
## 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
## 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 2 2 2 2 0 2 2 2 2
## 2 2 0 0 2 2 2 2 0 2 0 2 0 2 2 0 0 2 2 2 2 2 0 2 2 2 2 0 2 2 2 0 2 2 2 0 2
## 2 0]
centros = np.array(kmedias.cluster_centers_)
print(centros)
# Los dibuja sobre el plano principal
## [[5.9016129 2.7483871 4.39354839 1.43387097]
## [5.006 3.418 1.464 0.244 ]
## [6.85 3.07368421 5.74210526 2.07105263]]
pca = PCA(n_components=2)
componentes = pca.fit_transform(iris_tempo)
print(componentes[0:20])
## [[-2.68420713 0.32660731]
## [-2.71539062 -0.16955685]
## [-2.88981954 -0.13734561]
## [-2.7464372 -0.31112432]
## [-2.72859298 0.33392456]
## [-2.27989736 0.74778271]
## [-2.82089068 -0.08210451]
## [-2.62648199 0.17040535]
## [-2.88795857 -0.57079803]
## [-2.67384469 -0.1066917 ]
## [-2.50652679 0.65193501]
## [-2.61314272 0.02152063]
## [-2.78743398 -0.22774019]
## [-3.22520045 -0.50327991]
## [-2.64354322 1.1861949 ]
## [-2.38386932 1.34475434]
## [-2.6225262 0.81808967]
## [-2.64832273 0.31913667]
## [-2.19907796 0.87924409]
## [-2.58734619 0.52047364]]
print(iris.shape)
## (150, 5)
print(componentes.shape)
# Gráfico
## (150, 2)
plt.scatter(componentes[:, 0], componentes[:, 1],c=kmedias.predict(iris_tempo))
plt.xlabel('componente 1')
plt.ylabel('componente 2')
plt.title('3 Cluster K-Medias')
plt.show()
# Graficos de barras de los clusters
colores_1 = ['#CF8EF8', '#523C81', '#D2D132', '#59C951', '#E5826C']
plt.figure(1,figsize=(18,8))
# Plotea Centro 1
plt.subplot(1, 3, 1)
y = centros[:1, :].tolist()[0]
null=plt.bar(range(len(y)), y, 1/1.5, color=colores_1)
null=plt.xticks(range(iris.shape[1]), iris.columns,rotation=45)
# Plotea Centro 2
plt.subplot(1, 3, 2)
y= centros[1:2, :].tolist()[0]
null=plt.bar(range(len(y)), y, 1/1.5, color=colores_1)
null=plt.xticks(range(iris.shape[1]), iris.columns,rotation=45)
# Plotea Centro 3
plt.subplot(1, 3, 3)
y = centros[2:3, :].tolist()[0]
null=plt.bar(range(len(y)), y, 1/1.5, color=colores_1)
null=plt.xticks(range(iris.shape[1]), iris.columns,rotation=45)
plt.show()
plt.close()
# RADAR PLOT para interpretar
# ===========================
df = pd.DataFrame()
for i in range(iris.shape[1]):
df = pd.concat([df,pd.DataFrame({iris.columns[i]:centros_trans[i,:].tolist()})],axis = 1)
df = pd.concat([df,pd.DataFrame({'grupo': ['Cluster-1','Cluster-2','Cluster-3']})],axis = 1)
print(df)
# Variables y Número de Variables
## s.largo s.ancho p.largo p.ancho tipo grupo
## 0 6.525 6.525 8.475 8.875 7.375 Cluster-1
## 1 7.700 9.475 7.625 7.750 6.750 Cluster-2
## 2 5.500 6.250 6.500 6.250 8.850 Cluster-3
variables=list(df)[0:5]
variables
## ['s.largo', 's.ancho', 'p.largo', 'p.ancho', 'tipo']
N = len(variables)
print(N)
# Ángulo de los ejes
## 5
angulos = [n / float(N) * 2 * pi for n in range(N)]
angulos+= angulos[:1]
# Inicializa el Radar
ax = plt.subplot(111, polar=True)
# En primer eje en la parte de arriba
ax.set_theta_offset(pi / 2)
ax.set_theta_direction(-1)
# Dibuja los ejes por variables + las etiquetas
null=plt.xticks(angulos[:-1], variables,rotation=45)
# Dibuja las etiquetas en Y
ax.set_rlabel_position(0)
null=plt.yticks([1,2,3,4,5,6,7,8,9,10], ["1","2","3","4","5","6","7","8","9","10"], color="grey", size=7)
plt.ylim(0,10)
# Plotea cada cluster (grupo) = una línea de datos
# Cluster 1
## (0.0, 10.0)
valores=df.loc[0].drop('grupo').values.flatten().tolist()
valores += valores[:1]
ax.plot(angulos, valores, linewidth=1, linestyle='solid', label="Cluster-1")
ax.fill(angulos, valores, 'b', alpha=0.1)
# Cluster 2
valores=df.loc[1].drop('grupo').values.flatten().tolist()
valores += valores[:1]
ax.plot(angulos, valores, linewidth=1, linestyle='solid', label="Cluster-2")
ax.fill(angulos, valores, 'r', alpha=0.1)
# Cluster 3
valores=df.loc[2].drop('grupo').values.flatten().tolist()
valores += valores[:1]
ax.plot(angulos, valores, linewidth=1, linestyle='solid', label="Cluster-3")
ax.fill(angulos, valores, 'b', alpha=0.1)
# Agrega la leyenda
plt.legend(loc='upper right', bbox_to_anchor=(0.1, 0.1))
plt.show()
plt.close()
# Ejemplo 4. Ejemplo con datos Servicio al Cliente
#os.chdir("/Users/oldemarrodriguez/Google Drive/MDCurso/Datos")
print(os.getcwd())
## /Users/freddy/Documents/Cursos/UCR/IE_0217/CursoVerano/MaterialCurso/Clases/Semana07/pyClase20/pyModulo12
datos = pd.read_csv('../Datos/EjemploClientesCorregidaEdad.csv',delimiter=';',decimal=",",index_col=0)
print(datos)
## Edad/10 Antiguedad ... Prestigio Empresa Calidad Servicio
## Nombre Cliente ...
## Ariana 2.5 1 ... 7.0 6.6
## Guiselle 2.4 0 ... 9.8 5.4
## Francisco 2.8 7 ... 9.6 8.5
## Griselda 2.3 0 ... 2.8 5.4
## Damaris 4.9 6 ... 2.6 3.3
## Johana 3.2 4 ... 4.2 7.2
## Bernal 2.6 0 ... 9.6 6.5
## Freddy 2.3 4 ... 5.6 4.5
## Estafania 2.5 4 ... 6.0 7.6
## Laura 2.9 0 ... 8.4 6.5
## Arnoldo 3.2 13 ... 7.0 3.9
## Beatriz 2.7 5 ... 7.6 5.4
## Rebeca 2.2 0 ... 9.4 4.6
## Sofia 3.1 5 ... 8.8 2.4
## Ingrid 2.7 5 ... 7.4 4.0
## Rocio 4.2 4 ... 5.2 5.7
## Karen 4.3 5 ... 8.0 5.4
## Luis 2.4 4 ... 8.0 8.8
## Pedro 2.1 1 ... 9.6 6.0
## Lorena 3.0 4 ... 4.6 4.5
## Elena 3.1 5 ... 8.4 5.6
## Julian 4.0 5 ... 5.0 1.5
## Natalie 3.4 1 ... 9.6 4.6
## Shirley 2.4 0 ... 5.2 3.0
## Andres 3.8 3 ... 6.4 6.9
## Alejandro 2.6 6 ... 6.6 3.2
## Grace 2.8 0 ... 5.8 5.5
## Nuria 2.1 0 ... 7.4 2.3
## Flor 2.4 1 ... 6.6 2.5
## Roberto 4.1 8 ... 6.6 3.2
## Victor 2.7 3 ... 8.2 5.2
## Arturo 3.4 5 ... 8.2 6.5
## Maritza 2.4 4 ... 8.2 5.8
## Diana 2.4 1 ... 6.4 2.6
## Juan 2.3 4 ... 4.6 8.1
## Guillermo 1.9 1 ... 8.8 4.8
## Silvia 2.5 2 ... 8.6 5.5
##
## [37 rows x 12 columns]
datos.head()
## Edad/10 Antiguedad ... Prestigio Empresa Calidad Servicio
## Nombre Cliente ...
## Ariana 2.5 1 ... 7.0 6.6
## Guiselle 2.4 0 ... 9.8 5.4
## Francisco 2.8 7 ... 9.6 8.5
## Griselda 2.3 0 ... 2.8 5.4
## Damaris 4.9 6 ... 2.6 3.3
##
## [5 rows x 12 columns]
datos.shape
## (37, 12)
datos.dropna().describe()
# Ejecuta k-medias con 3 clusters
## Edad/10 Antiguedad ... Prestigio Empresa Calidad Servicio
## count 37.000000 37.00000 ... 37.000000 37.000000
## mean 2.881081 3.27027 ... 7.075676 5.108108
## std 0.707436 2.83479 ... 1.920851 1.816648
## min 1.900000 0.00000 ... 2.600000 1.500000
## 25% 2.400000 1.00000 ... 5.800000 3.900000
## 50% 2.700000 4.00000 ... 7.400000 5.400000
## 75% 3.200000 5.00000 ... 8.400000 6.500000
## max 4.900000 13.00000 ... 9.800000 8.800000
##
## [8 rows x 12 columns]
kmedias = KMeans(n_clusters=3)
kmedias.fit(datos)
## KMeans(n_clusters=3)
print(kmedias.predict(datos))
## [1 1 2 0 0 0 1 2 0 1 2 2 1 2 2 2 2 2 1 0 2 0 0 0 0 2 0 1 1 2 1 2 2 0 0 1 1]
centros = np.array(kmedias.cluster_centers_)
centros
# Codo de Jambu
## array([[3.08333333, 2.66666667, 5.33333333, 7.33333333, 4.33333333,
## 9.66666667, 2.00833333, 9.35 , 5.6 , 5.68333333,
## 5.26666667, 5.01666667],
## [2.39090909, 0.81818182, 6.34545455, 8.32727273, 8.23636364,
## 9.7 , 4.45454545, 9.18181818, 7.4 , 7.4 ,
## 8.49090909, 5.08181818],
## [3.09285714, 5.71428571, 6.61428571, 8.04285714, 7.08571429,
## 9.57857143, 3.71428571, 8.55714286, 7.05714286, 7.41428571,
## 7.51428571, 5.20714286]])
Nc = range(1, 20)
kmediasList = [KMeans(n_clusters=i) for i in Nc]
varianza = [kmediasList[i].fit(datos).score(datos) for i in range(len(kmediasList))]
plt.plot(Nc,varianza,'o-')
plt.xlabel('Número de clústeres')
plt.ylabel('Varianza explicada por cada cluster (Inercia Interclases)')
plt.title('Codo de Jambu')
plt.show()
Nc = range(1, 20)
kmediasList = [KMeans(n_clusters=i) for i in Nc]
varianza = [kmediasList[i].fit(datos).inertia_ for i in range(len(kmediasList))]
plt.plot(Nc,varianza,'o-')
plt.xlabel('Número de clústeres')
plt.ylabel('Varianza explicada por cada cluster (Inercia Interclases)')
plt.title('Codo de Jambu')
plt.show()
# En este caso no hay mucha claridad, K=3 o K=7 son buenas opciones
# LOS TRES JUNTOS
colores_1 = ['#C4F6C2','#03864B', '#AF960F','#F124A3','#FEF61E','#10855C',
'#441308','#4C19BE','#E74D50','#45DC46','#AA27B6','#2B757E']
#plt.figure(1,figsize=(26,20))
# Plotea Centro 1
plt.subplot(3, 1, 1)
y = centros[:1, :].tolist()[0]
null=plt.bar(range(len(y)), y, 1/1.5, color=colores_1)
null=plt.xticks(range(datos.shape[1]), datos.columns)
null =plt.tick_params(labelbottom=False)
# Plotea Centro 2
plt.subplot(3, 1, 2)
y= centros[1:2, :].tolist()[0]
null=plt.bar(range(len(y)), y, 1/1.5, color=colores_1)
null=plt.xticks(range(datos.shape[1]), datos.columns)
null =plt.tick_params(labelbottom=False)
# Plotea Centro 3
plt.subplot(3, 1, 3)
y = centros[2:3, :].tolist()[0]
null=plt.bar(range(len(y)), y, 1/1.5, color=colores_1)
null=plt.xticks(range(datos.shape[1]), datos.columns,rotation=30,fontsize=5)
plt.show()
# RADAR PLOT para interpretar
# ===========================
datos
## Edad/10 Antiguedad ... Prestigio Empresa Calidad Servicio
## Nombre Cliente ...
## Ariana 2.5 1 ... 7.0 6.6
## Guiselle 2.4 0 ... 9.8 5.4
## Francisco 2.8 7 ... 9.6 8.5
## Griselda 2.3 0 ... 2.8 5.4
## Damaris 4.9 6 ... 2.6 3.3
## Johana 3.2 4 ... 4.2 7.2
## Bernal 2.6 0 ... 9.6 6.5
## Freddy 2.3 4 ... 5.6 4.5
## Estafania 2.5 4 ... 6.0 7.6
## Laura 2.9 0 ... 8.4 6.5
## Arnoldo 3.2 13 ... 7.0 3.9
## Beatriz 2.7 5 ... 7.6 5.4
## Rebeca 2.2 0 ... 9.4 4.6
## Sofia 3.1 5 ... 8.8 2.4
## Ingrid 2.7 5 ... 7.4 4.0
## Rocio 4.2 4 ... 5.2 5.7
## Karen 4.3 5 ... 8.0 5.4
## Luis 2.4 4 ... 8.0 8.8
## Pedro 2.1 1 ... 9.6 6.0
## Lorena 3.0 4 ... 4.6 4.5
## Elena 3.1 5 ... 8.4 5.6
## Julian 4.0 5 ... 5.0 1.5
## Natalie 3.4 1 ... 9.6 4.6
## Shirley 2.4 0 ... 5.2 3.0
## Andres 3.8 3 ... 6.4 6.9
## Alejandro 2.6 6 ... 6.6 3.2
## Grace 2.8 0 ... 5.8 5.5
## Nuria 2.1 0 ... 7.4 2.3
## Flor 2.4 1 ... 6.6 2.5
## Roberto 4.1 8 ... 6.6 3.2
## Victor 2.7 3 ... 8.2 5.2
## Arturo 3.4 5 ... 8.2 6.5
## Maritza 2.4 4 ... 8.2 5.8
## Diana 2.4 1 ... 6.4 2.6
## Juan 2.3 4 ... 4.6 8.1
## Guillermo 1.9 1 ... 8.8 4.8
## Silvia 2.5 2 ... 8.6 5.5
##
## [37 rows x 12 columns]
centros
## array([[3.08333333, 2.66666667, 5.33333333, 7.33333333, 4.33333333,
## 9.66666667, 2.00833333, 9.35 , 5.6 , 5.68333333,
## 5.26666667, 5.01666667],
## [2.39090909, 0.81818182, 6.34545455, 8.32727273, 8.23636364,
## 9.7 , 4.45454545, 9.18181818, 7.4 , 7.4 ,
## 8.49090909, 5.08181818],
## [3.09285714, 5.71428571, 6.61428571, 8.04285714, 7.08571429,
## 9.57857143, 3.71428571, 8.55714286, 7.05714286, 7.41428571,
## 7.51428571, 5.20714286]])
centros_trans = centros.T
centros_trans
## array([[3.08333333, 2.39090909, 3.09285714],
## [2.66666667, 0.81818182, 5.71428571],
## [5.33333333, 6.34545455, 6.61428571],
## [7.33333333, 8.32727273, 8.04285714],
## [4.33333333, 8.23636364, 7.08571429],
## [9.66666667, 9.7 , 9.57857143],
## [2.00833333, 4.45454545, 3.71428571],
## [9.35 , 9.18181818, 8.55714286],
## [5.6 , 7.4 , 7.05714286],
## [5.68333333, 7.4 , 7.41428571],
## [5.26666667, 8.49090909, 7.51428571],
## [5.01666667, 5.08181818, 5.20714286]])
df = pd.DataFrame()
for i in range(datos.shape[1]):
df = pd.concat([df,pd.DataFrame({datos.columns[i]:centros_trans[i,:].tolist()})],axis = 1)
df = pd.concat([df,pd.DataFrame({'grupo': ['Cluster-1','Cluster-2','Cluster-3']})],axis = 1)
print(df)
# Variables y Número de Variables
## Edad/10 Antiguedad ... Calidad Servicio grupo
## 0 3.083333 2.666667 ... 5.016667 Cluster-1
## 1 2.390909 0.818182 ... 5.081818 Cluster-2
## 2 3.092857 5.714286 ... 5.207143 Cluster-3
##
## [3 rows x 13 columns]
variables = list(df)[0:12]
variables
## ['Edad/10', 'Antiguedad', 'Espacios Parqueo', 'Velocidad Cajas', 'Distribucion Productos', 'Atencion Empleados', 'Calidad Instalaciones', 'Ubicacion', 'Limpieza', 'Variedad Productos', 'Prestigio Empresa', 'Calidad Servicio']
N = len(variables)
print(N)
# Ángulo de los ejes
## 12
angulos = [n / float(N) * 2 * pi for n in range(N)]
angulos+= angulos[:1]
# Inicializa el Radar
ax = plt.subplot(111, polar=True)
# En primer eje en la parte de arriba
ax.set_theta_offset(pi / 2)
ax.set_theta_direction(-1)
# Dibuja los ejes por variables + las etiquetas
null=plt.xticks(angulos[:-1], variables)
# Dibuja las etiquetas en Y
ax.set_rlabel_position(0)
null=plt.yticks([1,2,3,4,5,6,7,8,9,10], ["1","2","3","4","5","6","7","8","9","10"], color="grey", size=7)
plt.ylim(0,10)
# Plotea cada cluster (grupo) = una línea de datos
# Cluster 1
## (0.0, 10.0)
valores=df.loc[0].drop('grupo').values.flatten().tolist()
valores += valores[:1]
ax.plot(angulos, valores, linewidth=1, linestyle='solid', label="Cluster-1")
ax.fill(angulos, valores, 'b', alpha=0.1)
# Cluster 2
valores=df.loc[1].drop('grupo').values.flatten().tolist()
valores += valores[:1]
ax.plot(angulos, valores, linewidth=1, linestyle='solid', label="Cluster-2")
ax.fill(angulos, valores, 'r', alpha=0.1)
# Cluster 3
valores=df.loc[2].drop('grupo').values.flatten().tolist()
valores += valores[:1]
ax.plot(angulos, valores, linewidth=1, linestyle='solid', label="Cluster-3")
ax.fill(angulos, valores, 'b', alpha=0.1)
# Agrega la leyenda
plt.legend(loc='upper right', bbox_to_anchor=(0.1, 0.1))
plt.show()
plt.close()
# Los dibuja sobre el plano principal los clusters de k-medias
pca = PCA(n_components=2)
componentes = pca.fit_transform(datos)
componentes
## array([[-2.29713786, -1.0440986 ],
## [-3.67955322, -1.96190882],
## [-0.62772032, 4.64231098],
## [ 1.0132489 , -5.21164881],
## [ 9.6383012 , -1.77660147],
## [ 2.69029011, -1.06384576],
## [-3.33779804, -1.8576653 ],
## [ 1.25061775, 0.34179433],
## [ 3.41296888, -1.80612147],
## [-3.256672 , -1.68846677],
## [ 5.01277194, 7.55924114],
## [ 0.45713703, 2.00890385],
## [-4.31444668, -1.1532299 ],
## [-0.77814906, 2.71798916],
## [ 2.03613873, 1.03552109],
## [ 1.76558006, 0.01137745],
## [ 1.02227888, 1.59870929],
## [-3.14165189, 2.88770514],
## [-5.2959146 , 0.4575491 ],
## [ 3.03594357, -0.8969674 ],
## [-1.40718438, 3.11033148],
## [ 5.15684301, -1.01284596],
## [-0.50563026, -2.36536284],
## [ 0.12202622, -4.53423404],
## [ 2.63071112, -1.92036543],
## [ 1.12329306, 2.55134427],
## [ 1.08623432, -4.6862166 ],
## [-3.38481021, -1.52501917],
## [-1.608607 , -0.98540369],
## [ 1.9931198 , 4.62767147],
## [-2.49813693, 1.09450718],
## [-0.46391975, 2.41542231],
## [-2.3310668 , 2.29942888],
## [ 1.05653443, -3.86688064],
## [ 2.9049432 , -0.67917184],
## [-4.12791536, -0.60456319],
## [-4.35266784, 1.28081056]])
print(datos.shape)
## (37, 12)
print(componentes.shape)
## (37, 2)
plt.scatter(componentes[:, 0], componentes[:, 1],c=kmedias.predict(datos))
plt.xlabel('componente 1')
plt.ylabel('componente 2')
plt.title('3 Cluster K-Medias')
plt.show()
Para comprender el método se deben analizar sub-criterios que permiten establecer la manera de agrupación de un conjunto de datos.
Conocido como “Clusterización Jerárquica”, el enfoque aglomerativo o enfoque ascendente considera cada dato (muestra) como si se tratara como un solo clúster y luego se fusionan o aglomeran por pares en forma sucesiva hasta que todos los clústeres se hayan fusionado en uno solo. La agrupación parte de determinado nivel de agrupamiento y criterios que veremos a continuación.
En esta técnica, inicialmente cada punto de datos se considera como un clúster individual. En cada iteración, los grupos similares se fusionan con otros grupos hasta que se forma un grupo o grupos K.
El algoritmo básico de algomeración consiste en:
La operación clave es el cálculo de la proximidad de dos clústeres.
En un agrupamiento divisivo (esta vez de arriba hacia abajo), un incia con un solo clúster de todas las muestras sque se va dividiendo recursivamente en dos clústeres (al menos similares) hasta que haya un clúster para cada observación. A la inversa del método anterior.
Esta técnica no se usa tanto que la anterior, se consideran todos los puntos de datos como un único clúster:
Se le llama se le llama agrupamiento jerárquico divisiva ya que se hace repetidamente la división hasta obtener n clústeres,
El objetivo es combinar repetidamente dos clústers cercanos (de nuevo el criterio de distancia es euclidiana por omisión pero podría ser otro acorde al tipo de tipos) en un clúster más grande.
El algoritmo es el siguiente:
Los métodos de cálculo de distancia permiten 5 tipos de formas algorítmicas.
Se calculan las distancias máximas entres clústers antes de la fusión.
Se calculan las distancias mínima entres elementos de cada clúster antes de la fusión. Permite ubicar valores atípicos.
Se calculan la distancia completa pero se usa la distancia media entre los pares del clúster.
Se localiza el centroide de cada clúster y luego se calcula la distancia entre los centroides antes de fucionarlos.
En este método se consideran todos los clústeres y el algoritmo calcula la suma de las distancias cuadradas dentro de los clústeres y las fusiona para minimizarlas.
Desde un punto de vista estadística, el proceso de aglomeración conduce a una reducción de la varianza de cada clúster resultante.
La elección del método vinculación depende totalmente cada quien y no hay un método rápido y robusto que siempre dé buenos resultados. Diferentes métodos de vinculación conducen a diferentes clústering.
Cómo se indicó anteriormente el criterio de “distancia” es habitualmente euclidiana pero se pueden usar otros criterios dependiendo de la caracterizacón de los datos.
Existen al menos 4 que son utilizados los más utilizados.
Es la distancia ordinaria en línea recta entre dos puntos en el espacio euclidiano. Con esta distancia, el espacio euclidiano se convierte en un espacio métrico.
Es similar a la euclidiana, con la condición que la distancia se calcula sumando el valor absoluto de la diferencia entre las dimensiones. Por ejemplo, la distancia de Manhattan implica moverse en línea recta, primero a lo lardo de un eje y luego junto con el otro.
Toma en cuenta la forma de las variables, más que sus valores. Tiende a asociar observaciones que tienen las mismas variables máxima y mínima, independientemente de su valor efectivo.
Para ejemplizar el método el siguiente segmento de código en Python muestra el contexto de Clusterización Jerárquica.
## Clusterización Jerárquica
# Import the dendrogram function and the ward clustering function from SciPy
from scipy.cluster.hierarchy import dendrogram, ward, single, complete,average,linkage, fcluster
from scipy.spatial.distance import pdist
# f cluster para los centros
# Simulación del clustering jeráquico
mglearn.plots.plot_agglomerative()
plt.show()
plt.close()
Es la forma de gráfico que permite observar las agrupaciones resultantes.
En los siguientes segmentos de código se muestran los diferentes métodos de agrupamiento.
# Ejemplo 1. Datos simulados con dos variables
X, y = make_blobs(random_state=0, n_samples=20, n_features = 3)
X = pd.DataFrame(X).abs()
X.columns = ["X1","X2","X3"]
print(X)
## X1 X2 X3
## 0 0.180614 0.131432 4.705366
## 1 1.146194 1.558149 2.778408
## 2 2.432693 0.960464 3.067147
## 3 0.409572 4.061638 3.569659
## 4 2.242389 3.797911 4.600468
## 5 1.555621 7.468936 10.392967
## 6 0.643213 4.351152 3.518008
## 7 0.707008 1.078266 1.925452
## 8 1.727676 8.146824 8.497235
## 9 1.706178 8.260853 9.245284
## 10 0.188137 0.887168 2.532019
## 11 0.328146 1.351517 2.455377
## 12 0.121901 0.531193 0.984677
## 13 0.794688 5.713992 1.680796
## 14 2.057082 4.788099 2.634408
## 15 1.009709 4.984355 0.491771
## 16 0.227734 8.482240 8.908921
## 17 1.474195 6.180889 8.633533
## 18 1.927033 7.481832 8.532508
## 19 1.251468 3.343033 2.432194
print(y)
# Agregación de:
## [1 1 1 0 0 2 0 1 2 2 1 1 1 0 0 0 2 2 2 0]
ward_res = ward(X) #Ward
single_res = single(X) #Salto mínimo
complete_res = complete(X) #Salto Máximo
average_res = average(X) #Promedio
# Plotea el dendograma
plt.figure(figsize=(13,10))
null=dendrogram(average_res)
plt.show()
plt.close()
plt.figure(figsize=(13,10))
null=dendrogram(complete_res)
plt.show()
plt.close()
plt.figure(figsize=(13,10))
null=dendrogram(single_res)
plt.show()
plt.close()
plt.figure(figsize=(13,10))
d = dendrogram(ward_res)
# Agrega cortes con 2 y 3 clústeres
ax = plt.gca()
limites = ax.get_xbound()
ax.plot(limites, [15.5, 15.5], '--', c='k')
ax.plot(limites, [5, 5], '--', c='k')
ax.text(limites[1], 15.5, ' dos clústeres', va='center', fontdict={'size': 15})
ax.text(limites[1], 5, ' tres clústeres', va='center', fontdict={'size': 15})
plt.xlabel("Orden en el eje X")
plt.ylabel("Distancia o Agregación")
plt.show()
plt.close()
Otra forma de observar los resultados es mediante gráficos de barras. Similar a como se observó en la parte de K-medias.
# Gráficos de barras :
def centroide(num_cluster, datos, clusters):
ind = clusters == num_cluster
return(pd.DataFrame(datos[ind].mean()).T)
grupos = fcluster(linkage(pdist(X), method='ward'),3,'distance')
centros = np.array(pd.concat([centroide(1,X,grupos),centroide(2,X,grupos),centroide(3,X,grupos)]))
colores_1 = ['#CF8EF8', '#523C81', '#D2D132', '#59C951', '#E5826C']
plt.figure(1,figsize=(18,8))
# Plotea Centro 1
plt.subplot(1, 3, 1)
y = centros[:1, :].tolist()[0]
null=plt.bar(range(len(y)), y, 1/1.5, color=colores_1)
null=plt.xticks(range(X.shape[1]), X.columns)
# Plotea Centro 2
plt.subplot(1, 3, 2)
y= centros[1:2, :].tolist()[0]
null=plt.bar(range(len(y)), y, 1/1.5, color=colores_1)
null=plt.xticks(range(X.shape[1]), X.columns)
# Plotea Centro 3
plt.subplot(1, 3, 3)
y= centros[2:3, :].tolist()[0]
null=plt.bar(range(len(y)), y, 1/1.5, color=colores_1)
null=plt.xticks(range(X.shape[1]), X.columns)
plt.show()
plt.close()
Otra forma de observar los resultados es mediante gráficos radar, de la misma manera que se presentaron los resultados en la parte de K-medias.
# RADAR PLOT para interpretar
# ===========================
centros_trans = centros.T
centros_trans
## array([[1.43640617, 0.8206799 , 0.18061434],
## [7.67026242, 1.06112633, 0.13143174],
## [9.03507453, 2.29051355, 4.70536631]])
df = pd.DataFrame()
for i in range(X.shape[1]):
df = pd.concat([df,pd.DataFrame({X.columns[i]:centros_trans[i,:].tolist()})],axis = 1)
df = pd.concat([df,pd.DataFrame({'grupo': ['Cluster-1','Cluster-2','Cluster-3']})],axis = 1)
print(df)
# Variables y Número de Variables
## X1 X2 X3 grupo
## 0 1.436406 7.670262 9.035075 Cluster-1
## 1 0.820680 1.061126 2.290514 Cluster-2
## 2 0.180614 0.131432 4.705366 Cluster-3
variables=list(df)[0:3]
variables
## ['X1', 'X2', 'X3']
N = len(variables)
print(N)
# Ángulo de los ejes
## 3
angulos = [n / float(N) * 2 * pi for n in range(N)]
angulos+= angulos[:1]
# Inicializa el Radar
ax = plt.subplot(111, polar=True)
# En primer eje en la parte de arriba
ax.set_theta_offset(pi / 2)
ax.set_theta_direction(-1)
# Dibuja los ejes por variables + las etiquetas
null=plt.xticks(angulos[:-1], variables)
# Dibuja las etiquetas en Y
ax.set_rlabel_position(0)
null=plt.yticks([1,2,3,4,5,6,7,8,9,10], ["1","2","3","4","5","6","7","8","9","10"], color="grey", size=7)
plt.ylim(0,10)
# Plotea cada cluster (grupo) = una línea de datos
# Cluster 1
## (0.0, 10.0)
valores=df.loc[0].drop('grupo').values.flatten().tolist()
valores += valores[:1]
ax.plot(angulos, valores, linewidth=1, linestyle='solid', label="Cluster-1")
ax.fill(angulos, valores, 'b', alpha=0.1)
# Cluster 2
valores=df.loc[1].drop('grupo').values.flatten().tolist()
valores += valores[:1]
ax.plot(angulos, valores, linewidth=1, linestyle='solid', label="Cluster-2")
ax.fill(angulos, valores, 'r', alpha=0.1)
# Cluster 3
valores=df.loc[2].drop('grupo').values.flatten().tolist()
valores += valores[:1]
ax.plot(angulos, valores, linewidth=1, linestyle='solid', label="Cluster-3")
ax.fill(angulos, valores, 'b', alpha=0.1)
# Agrega la leyenda
plt.legend(loc='upper right', bbox_to_anchor=(0.1, 0.1))
plt.show()
plt.close()
# Ejemplo 2. Datos de Estudiantes
#os.chdir("/Users/oldemarrodriguez/Google Drive/MDCurso/Datos")
print(os.getcwd())
## /Users/freddy/Documents/Cursos/UCR/IE_0217/CursoVerano/MaterialCurso/Clases/Semana07/pyClase20/pyModulo12
datos = pd.read_csv('../Datos/EjemploEstudiantes.csv',delimiter=';',decimal=",",index_col=0)
print(datos)
## Matematicas Ciencias Espanol Historia EdFisica
## Lucia 7.0 6.5 9.2 8.6 8.0
## Pedro 7.5 9.4 7.3 7.0 7.0
## Ines 7.6 9.2 8.0 8.0 7.5
## Luis 5.0 6.5 6.5 7.0 9.0
## Andres 6.0 6.0 7.8 8.9 7.3
## Ana 7.8 9.6 7.7 8.0 6.5
## Carlos 6.3 6.4 8.2 9.0 7.2
## Jose 7.9 9.7 7.5 8.0 6.0
## Sonia 6.0 6.0 6.5 5.5 8.7
## Maria 6.8 7.2 8.7 9.0 7.0
print(datos.head())
## Matematicas Ciencias Espanol Historia EdFisica
## Lucia 7.0 6.5 9.2 8.6 8.0
## Pedro 7.5 9.4 7.3 7.0 7.0
## Ines 7.6 9.2 8.0 8.0 7.5
## Luis 5.0 6.5 6.5 7.0 9.0
## Andres 6.0 6.0 7.8 8.9 7.3
print(datos.shape)
# Agregación de:
## (10, 5)
ward_res = ward(datos) #Ward
single_res = single(datos) #Salto mínimo
complete_res = complete(datos) #Salto Máximo
average_res = average(datos) #Promedio
# Plotea el dendograma
plt.figure(figsize=(13,10))
null=dendrogram(average_res,labels= datos.index.tolist())
plt.show()
plt.close()
plt.figure(figsize=(13,10))
null=dendrogram(complete_res,labels= datos.index.tolist())
plt.show()
plt.close()
plt.figure(figsize=(13,10))
null=dendrogram(single_res,labels= datos.index.tolist())
plt.show()
plt.close()
plt.figure(figsize=(13,10))
null=dendrogram(ward_res,labels= datos.index.tolist())
# Agrega cortes con 2 y 3 clústeres
ax = plt.gca()
limites = ax.get_xbound()
ax.plot(limites, [7.25, 7.25], '--', c='k')
ax.plot(limites, [4, 4], '--', c='k')
ax.text(limites[1], 7.25, ' dos clústeres', va='center', fontdict={'size': 15})
ax.text(limites[1], 4, ' tres clústeres', va='center', fontdict={'size': 15})
plt.xlabel("Orden en el eje X")
plt.ylabel("Distancia o Agregación")
plt.show()
plt.close()
# Gráficos de barras :
grupos = fcluster(linkage(pdist(datos), method='ward'),3,'distance')
centros = np.array(pd.concat([centroide(1,datos,grupos),centroide(2,datos,grupos),centroide(3,datos,grupos)]))
colores_1 = ['#CF8EF8', '#523C81', '#D2D132', '#59C951', '#E5826C']
# Plotea Centro 1
plt.figure(1,figsize=(18,8))
plt.subplot(1, 3, 1)
y = centros[:1,:].tolist()[0]
null=plt.bar(range(len(y)), y, 1/1.5, color=colores_1)
null=plt.xticks(range(datos.shape[1]), datos.columns)
# Plotea Centro 2
plt.subplot(1, 3, 2)
y= centros[1:2, :].tolist()[0]
null=plt.bar(range(len(y)), y, 1/1.5, color=colores_1)
null=plt.xticks(range(datos.shape[1]), datos.columns)
# Plotea Centro 3
plt.subplot(1, 3, 3)
y = centros[2:3, :].tolist()[0]
null=plt.bar(range(len(y)), y, 1/1.5, color=colores_1)
null=plt.xticks(range(datos.shape[1]), datos.columns)
plt.show()
plt.close()
# RADAR PLOT para interpretar
# ===========================
centros_trans = centros.T
centros_trans
## array([[7.7 , 5.5 , 6.525],
## [9.475, 6.25 , 6.525],
## [7.625, 6.5 , 8.475],
## [7.75 , 6.25 , 8.875],
## [6.75 , 8.85 , 7.375]])
df = pd.DataFrame()
for i in range(datos.shape[1]):
df = pd.concat([df,pd.DataFrame({datos.columns[i]:centros_trans[i,:].tolist()})],axis = 1)
df = pd.concat([df,pd.DataFrame({'grupo': ['Cluster-1','Cluster-2','Cluster-3']})],axis = 1)
print(df)
# Variables y Número de Variables
## Matematicas Ciencias Espanol Historia EdFisica grupo
## 0 7.700 9.475 7.625 7.750 6.750 Cluster-1
## 1 5.500 6.250 6.500 6.250 8.850 Cluster-2
## 2 6.525 6.525 8.475 8.875 7.375 Cluster-3
variables=list(df)[0:5]
variables
## ['Matematicas', 'Ciencias', 'Espanol', 'Historia', 'EdFisica']
N = len(variables)
print(N)
# Ángulo de los ejes
## 5
angulos = [n / float(N) * 2 * pi for n in range(N)]
angulos+= angulos[:1]
# Inicializa el Radar
ax = plt.subplot(111, polar=True)
# En primer eje en la parte de arriba
ax.set_theta_offset(pi / 2)
ax.set_theta_direction(-1)
# Dibuja los ejes por variables + las etiquetas
null=plt.xticks(angulos[:-1], variables)
# Dibuja las etiquetas en Y
ax.set_rlabel_position(0)
null=plt.yticks([1,2,3,4,5,6,7,8,9,10], ["1","2","3","4","5","6","7","8","9","10"], color="grey", size=7)
plt.ylim(0,10)
# Plotea cada cluster (grupo) = una línea de datos
# Cluster 1
## (0.0, 10.0)
valores=df.loc[0].drop('grupo').values.flatten().tolist()
valores += valores[:1]
ax.plot(angulos, valores, linewidth=1, linestyle='solid', label="Cluster-1")
ax.fill(angulos, valores, 'b', alpha=0.1)
# Cluster 2
valores=df.loc[1].drop('grupo').values.flatten().tolist()
valores += valores[:1]
ax.plot(angulos, valores, linewidth=1, linestyle='solid', label="Cluster-2")
ax.fill(angulos, valores, 'r', alpha=0.1)
# Cluster 3
valores=df.loc[2].drop('grupo').values.flatten().tolist()
valores += valores[:1]
ax.plot(angulos, valores, linewidth=1, linestyle='solid', label="Cluster-3")
ax.fill(angulos, valores, 'b', alpha=0.1)
# Agrega la leyenda
plt.legend(loc='upper right', bbox_to_anchor=(0.1, 0.1))
plt.show()
plt.close()
##_______________________________________________________________________________________
datos = pd.read_csv('../Datos/iris.csv',delimiter=';',decimal=".")
datos = datos.iloc[:,:4] #Elimina la variable categorica
print(datos)
## s.largo s.ancho p.largo p.ancho
## 0 5.1 3.5 1.4 0.2
## 1 4.9 3.0 1.4 0.2
## 2 4.7 3.2 1.3 0.2
## 3 4.6 3.1 1.5 0.2
## 4 5.0 3.6 1.4 0.2
## .. ... ... ... ...
## 145 6.7 3.0 5.2 2.3
## 146 6.3 2.5 5.0 1.9
## 147 6.5 3.0 5.2 2.0
## 148 6.2 3.4 5.4 2.3
## 149 5.9 3.0 5.1 1.8
##
## [150 rows x 4 columns]
print(datos.head())
## s.largo s.ancho p.largo p.ancho
## 0 5.1 3.5 1.4 0.2
## 1 4.9 3.0 1.4 0.2
## 2 4.7 3.2 1.3 0.2
## 3 4.6 3.1 1.5 0.2
## 4 5.0 3.6 1.4 0.2
print(datos.shape)
## (150, 4)
ward_res = ward(datos) #Ward
single_res = single(datos) #Salto mínimo
complete_res = complete(datos) #Salto Máximo
average_res = average(datos) #Promedio
null=dendrogram(average_res,labels= datos.index.tolist(),color_threshold=1.9,leaf_rotation=90)
plt.show()
plt.close()
plt.figure(figsize=(13,10))
null=dendrogram(complete_res,labels= datos.index.tolist(),color_threshold=3.5,leaf_rotation=90)
plt.show()
plt.close()
plt.figure(figsize=(13,10))
null=dendrogram(single_res,labels= datos.index.tolist(),color_threshold=0.7,leaf_rotation=90)
plt.show()
plt.close()
## Agregando cortes en el dendograma
plt.figure(figsize=(13,10))
null=dendrogram(ward_res,labels= datos.index.tolist(),color_threshold=8,leaf_rotation=90)
ax = plt.gca()
limites = ax.get_xbound()
ax.plot(limites, [20, 20], '--', c='k')
ax.plot(limites, [8, 8], '--', c='k')
ax.text(limites[1], 20, ' dos clústeres', va='center', fontdict={'size': 15})
ax.text(limites[1], 8, ' tres clústeres', va='center', fontdict={'size': 15})
plt.xlabel("Orden en el eje X")
plt.ylabel("Distancia o Agregación")
plt.show()
plt.close()
grupos = fcluster(linkage(pdist(datos), method='ward'),3,criterion='maxclust')
print(grupos)
## [1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
## 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
## 3 3 3 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 2 3 2 2 2 2 3 2 2 2 2
## 2 2 3 3 2 2 2 2 3 2 3 2 3 2 2 3 3 2 2 2 2 2 3 3 2 2 2 3 2 2 2 3 2 2 2 3 2
## 2 3]
centros = np.array(pd.concat([centroide(1,datos,grupos),centroide(2,datos,grupos),centroide(3,datos,grupos)]))
print(centros)
## [[5.006 3.418 1.464 0.244 ]
## [6.86944444 3.08611111 5.76944444 2.10555556]
## [5.9203125 2.7515625 4.4203125 1.434375 ]]
colores_1 = ['#CF8EF8', '#523C81', '#D2D132', '#59C951', '#E5826C']
# Plotea Centro 1
plt.figure(1,figsize=(18,8))
plt.subplot(1, 3, 1)
y = centros[:1,:].tolist()[0]
null=plt.bar(range(len(y)), y, 1/1.5, color=colores_1)
null=plt.xticks(range(datos.shape[1]), datos.columns)
# Plotea Centro 2
plt.subplot(1, 3, 2)
y= centros[1:2, :].tolist()[0]
null=plt.bar(range(len(y)), y, 1/1.5, color=colores_1)
null=plt.xticks(range(datos.shape[1]), datos.columns)
# Plotea Centro 3
plt.subplot(1, 3, 3)
y = centros[2:3, :].tolist()[0]
null=plt.bar(range(len(y)), y, 1/1.5, color=colores_1)
null=plt.xticks(range(datos.shape[1]), datos.columns)
plt.show()
plt.close()
##Radar Plot
centros_trans = centros.T
print(centros_trans)
## [[5.006 6.86944444 5.9203125 ]
## [3.418 3.08611111 2.7515625 ]
## [1.464 5.76944444 4.4203125 ]
## [0.244 2.10555556 1.434375 ]]
df = pd.DataFrame()
for i in range(datos.shape[1]):
df = pd.concat([df,pd.DataFrame({datos.columns[i]:centros_trans[i,:].tolist()})],axis = 1)
df = pd.concat([df,pd.DataFrame({'grupo': ['Cluster-1','Cluster-2','Cluster-3']})],axis = 1)
print(df)
## s.largo s.ancho p.largo p.ancho grupo
## 0 5.006000 3.418000 1.464000 0.244000 Cluster-1
## 1 6.869444 3.086111 5.769444 2.105556 Cluster-2
## 2 5.920312 2.751562 4.420312 1.434375 Cluster-3
variables=list(df)[0:4]
print(variables)
## ['s.largo', 's.ancho', 'p.largo', 'p.ancho']
N = len(variables)
print(N)
## Angulo de ejes
## 4
angulos = [n / float(N) * 2 * pi for n in range(N)]
angulos+= angulos[:1]
ax = plt.subplot(111, polar=True)
#Eeje a 90 grados
ax.set_theta_offset(pi / 2)
ax.set_theta_direction(-1)
null=plt.xticks(angulos[:-1], variables)
ax.set_rlabel_position(0)
null=plt.yticks([1,2,3,4,5,6,7,8,9,10], ["1","2","3","4","5","6","7","8","9","10"], color="grey", size=7)
plt.ylim(0,10)
#Graficando cada cluster (grupo) = una línea de datos
#Cluster 1
## (0.0, 10.0)
valores=df.loc[0].drop('grupo').values.flatten().tolist()
valores += valores[:1]
ax.plot(angulos, valores, linewidth=1, linestyle='solid', label="Cluster-1")
ax.fill(angulos, valores, 'b', alpha=0.1)
#Cluster 2
valores=df.loc[1].drop('grupo').values.flatten().tolist()
valores += valores[:1]
ax.plot(angulos, valores, linewidth=1, linestyle='solid', label="Cluster-2")
ax.fill(angulos, valores, 'r', alpha=0.1)
#Cluster 3
valores=df.loc[2].drop('grupo').values.flatten().tolist()
valores += valores[:1]
ax.plot(angulos, valores, linewidth=1, linestyle='solid', label="Cluster-3")
ax.fill(angulos, valores, 'b', alpha=0.1)
#Plot
plt.legend(loc='upper right', bbox_to_anchor=(0.1, 0.1))
plt.show()
plt.close()
###_______________________________________________________________________
datos = pd.read_csv('../Datos/EjemploClientesCorregidaEdad.csv',delimiter=';',decimal=",",index_col=0)
print(datos)
## Edad/10 Antiguedad ... Prestigio Empresa Calidad Servicio
## Nombre Cliente ...
## Ariana 2.5 1 ... 7.0 6.6
## Guiselle 2.4 0 ... 9.8 5.4
## Francisco 2.8 7 ... 9.6 8.5
## Griselda 2.3 0 ... 2.8 5.4
## Damaris 4.9 6 ... 2.6 3.3
## Johana 3.2 4 ... 4.2 7.2
## Bernal 2.6 0 ... 9.6 6.5
## Freddy 2.3 4 ... 5.6 4.5
## Estafania 2.5 4 ... 6.0 7.6
## Laura 2.9 0 ... 8.4 6.5
## Arnoldo 3.2 13 ... 7.0 3.9
## Beatriz 2.7 5 ... 7.6 5.4
## Rebeca 2.2 0 ... 9.4 4.6
## Sofia 3.1 5 ... 8.8 2.4
## Ingrid 2.7 5 ... 7.4 4.0
## Rocio 4.2 4 ... 5.2 5.7
## Karen 4.3 5 ... 8.0 5.4
## Luis 2.4 4 ... 8.0 8.8
## Pedro 2.1 1 ... 9.6 6.0
## Lorena 3.0 4 ... 4.6 4.5
## Elena 3.1 5 ... 8.4 5.6
## Julian 4.0 5 ... 5.0 1.5
## Natalie 3.4 1 ... 9.6 4.6
## Shirley 2.4 0 ... 5.2 3.0
## Andres 3.8 3 ... 6.4 6.9
## Alejandro 2.6 6 ... 6.6 3.2
## Grace 2.8 0 ... 5.8 5.5
## Nuria 2.1 0 ... 7.4 2.3
## Flor 2.4 1 ... 6.6 2.5
## Roberto 4.1 8 ... 6.6 3.2
## Victor 2.7 3 ... 8.2 5.2
## Arturo 3.4 5 ... 8.2 6.5
## Maritza 2.4 4 ... 8.2 5.8
## Diana 2.4 1 ... 6.4 2.6
## Juan 2.3 4 ... 4.6 8.1
## Guillermo 1.9 1 ... 8.8 4.8
## Silvia 2.5 2 ... 8.6 5.5
##
## [37 rows x 12 columns]
print(datos.head())
## Edad/10 Antiguedad ... Prestigio Empresa Calidad Servicio
## Nombre Cliente ...
## Ariana 2.5 1 ... 7.0 6.6
## Guiselle 2.4 0 ... 9.8 5.4
## Francisco 2.8 7 ... 9.6 8.5
## Griselda 2.3 0 ... 2.8 5.4
## Damaris 4.9 6 ... 2.6 3.3
##
## [5 rows x 12 columns]
print(datos.shape)
## (37, 12)
ward_res = ward(datos) #Ward
single_res = single(datos) #Salto mínimo
complete_res = complete(datos) #Salto Máximo
average_res = average(datos) #Promedio
null=dendrogram(average_res,labels= datos.index.tolist(),color_threshold=9.8)
plt.show()
plt.close()
plt.figure(figsize=(13,10))
null=dendrogram(complete_res,labels= datos.index.tolist(),color_threshold=13)
plt.show()
plt.close()
plt.figure(figsize=(13,10))
null=dendrogram(single_res,labels= datos.index.tolist(),color_threshold=6.5)
plt.show()
plt.close()
## Con divisiones
plt.figure(figsize=(13,10))
null=dendrogram(ward_res,labels= datos.index.tolist(),color_threshold=15)
ax = plt.gca()
limites = ax.get_xbound()
ax.plot(limites, [20, 20], '--', c='k')
ax.plot(limites, [15, 15], '--', c='k')
ax.plot(limites, [12.5, 12.5], '--', c='k')
ax.text(limites[1], 20, ' dos clústeres', va='center', fontdict={'size': 15})
ax.text(limites[1], 15, ' tres clústeres', va='center', fontdict={'size': 15})
ax.text(limites[1], 12.5, ' cinco clústeres', va='center', fontdict={'size': 15})
plt.xlabel("Orden en el eje X")
plt.ylabel("Distancia o Agregación")
plt.show()
plt.close()
numero_clusters = 3
grupos = fcluster(linkage(pdist(datos), method='ward'),numero_clusters,criterion='maxclust')
print(grupos)
## [2 2 3 1 1 1 2 1 1 2 3 3 2 3 3 1 3 3 2 1 3 3 1 1 1 3 1 2 2 3 3 3 3 1 1 2 2]
centro_lista = []
centros = np.array(pd.concat([centroide(i+1,datos,grupos) for i in range(numero_clusters)]))
print(centros)
## [[3.03846154 2.69230769 5.44615385 7.38461538 4.69230769 9.69230769
## 2.13846154 9.01538462 5.84615385 5.83076923 5.30769231 5.3 ]
## [2.36 0.6 6.22 8.34 8.12 9.7
## 4.7 9.16 7.36 7.44 8.52 5.07 ]
## [3.10714286 5.71428571 6.67142857 8.05714286 7.11428571 9.55714286
## 3.59285714 8.87142857 6.98571429 7.37142857 7.68571429 4.95714286]]
colores_1 = ['#C4F6C2','#F3864B', '#AF960F','#F124A3','#FEF61E','#10855C',
'#441308','#4C19BE','#E74D50','#45DC46','#AA27B6','#2B757E']
# Otra manera:
plt.figure(1,figsize=(25,20))
for i in range(numero_clusters):
null=plt.subplot(numero_clusters, 1, i+1)
min_limit = i
max_limit = i+1
y = centros[min_limit:max_limit,:].tolist()[0]
null=plt.bar(range(len(y)), y, 1/1.5, color=colores_1)
null=null=plt.xticks(range(datos.shape[1]), datos.columns,rotation=30,fontsize=10)
plt.show()
plt.close()
## RADAR PLOT
centros_trans = centros.T
print(centros_trans)
## [[3.03846154 2.36 3.10714286]
## [2.69230769 0.6 5.71428571]
## [5.44615385 6.22 6.67142857]
## [7.38461538 8.34 8.05714286]
## [4.69230769 8.12 7.11428571]
## [9.69230769 9.7 9.55714286]
## [2.13846154 4.7 3.59285714]
## [9.01538462 9.16 8.87142857]
## [5.84615385 7.36 6.98571429]
## [5.83076923 7.44 7.37142857]
## [5.30769231 8.52 7.68571429]
## [5.3 5.07 4.95714286]]
nombres = ["Cluster-%i" % (i+1) for i in range(numero_clusters)]
print(nombres)
## ['Cluster-1', 'Cluster-2', 'Cluster-3']
df = pd.DataFrame()
for i in range(datos.shape[1]):
df = pd.concat([df,pd.DataFrame({datos.columns[i]:centros_trans[i,:].tolist()})],axis = 1)
df = pd.concat([df,pd.DataFrame({'grupo': nombres})],axis = 1)
print(df)
## Edad/10 Antiguedad ... Calidad Servicio grupo
## 0 3.038462 2.692308 ... 5.300000 Cluster-1
## 1 2.360000 0.600000 ... 5.070000 Cluster-2
## 2 3.107143 5.714286 ... 4.957143 Cluster-3
##
## [3 rows x 13 columns]
max_limit = df.shape[1] -1
variables=list(df)[0:max_limit]
print(variables)
## ['Edad/10', 'Antiguedad', 'Espacios Parqueo', 'Velocidad Cajas', 'Distribucion Productos', 'Atencion Empleados', 'Calidad Instalaciones', 'Ubicacion', 'Limpieza', 'Variedad Productos', 'Prestigio Empresa', 'Calidad Servicio']
N = len(variables)
print(N)
## 12
angulos = [n / float(N) * 2 * pi for n in range(N)]
angulos+= angulos[:1]
ax = plt.subplot(111, polar=True)
ax.set_theta_offset(pi / 2)
ax.set_theta_direction(-1)
null=null=plt.xticks(angulos[:-1], variables)
ax.set_rlabel_position(0)
null=plt.yticks([1,2,3,4,5,6,7,8,9,10], ["1","2","3","4","5","6","7","8","9","10"], color="grey", size=7)
plt.ylim(0,10)
## (0.0, 10.0)
for i in range(numero_clusters):
valores=df.loc[i].drop('grupo').values.flatten().tolist()
valores += valores[:1]
ax.plot(angulos, valores, linewidth=1, linestyle='solid', label=nombres[i])
ax.fill(angulos, valores, 'b', alpha=0.1)
plt.legend(loc='upper right', bbox_to_anchor=(0.1, 0.1))
plt.show()
plt.close()